package org.framework.lazy.cloud.network.heartbeat.client.netty.permeate.tcp.socket;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.framework.lazy.cloud.network.heartbeat.client.config.NettyClientProperties;
import org.framework.lazy.cloud.network.heartbeat.client.netty.permeate.NettyClientPermeateServerVisitor;
import org.framework.lazy.cloud.network.heartbeat.client.netty.permeate.tcp.filter.NettyTcpClientPermeateServerVisitorFilter;
import org.framework.lazy.cloud.network.heartbeat.common.NettyClientVisitorContext;
import org.framework.lazy.cloud.network.heartbeat.common.NettyVisitorPortContext;
import org.framework.lazy.cloud.network.heartbeat.common.advanced.HandleChannelTypeAdvanced;
import org.framework.lazy.cloud.network.heartbeat.common.factory.EventLoopGroupFactory;
import org.framework.lazy.cloud.network.heartbeat.common.socket.PermeateVisitorSocket;
import org.framework.lazy.cloud.network.heartbeat.common.utils.ChannelAttributeKeyUtils;

import java.util.List;

/**
 * 内网穿透 客户端渗透服务端通道
 *
 * @see NettyVisitorPortContext
 * @see NettyClientVisitorContext
 */
@Slf4j
public class NettyTcpClientPermeateServerVisitorSocket implements PermeateVisitorSocket {

    private final NettyTcpClientPermeateServerVisitorFilter nettyTcpClientPermeateServerVisitorFilter;
    @Getter
    private final String clientId;
    @Getter
    private final int visitorPort;

    public NettyTcpClientPermeateServerVisitorSocket(NettyTcpClientPermeateServerVisitorFilter nettyTcpClientPermeateServerVisitorFilter, String clientId, int visitorPort) {
        this.nettyTcpClientPermeateServerVisitorFilter = nettyTcpClientPermeateServerVisitorFilter;
        this.clientId = clientId;
        this.visitorPort = visitorPort;
    }

    /**
     * 启动客户端本地端口渗透到服务端端口
     *
     */
    @Override
    public void start()  {

        PermeateVisitorSocket visitor = NettyVisitorPortContext.getVisitorSocket(visitorPort);
        if (visitor == null) {
            ServerBootstrap bootstrap = new ServerBootstrap();
            EventLoopGroup bossGroup = EventLoopGroupFactory.createBossGroup();
            EventLoopGroup workerGroup = EventLoopGroupFactory.createWorkerGroup();
            bootstrap
                    .group(bossGroup, workerGroup)
                    .channel(NioServerSocketChannel.class)


                    // 设置读缓冲区为2M
                    .childOption(ChannelOption.SO_RCVBUF, 2048 * 1024)
                    // 设置写缓冲区为1M
                    .childOption(ChannelOption.SO_SNDBUF, 1024 * 1024)


                    .childOption(ChannelOption.SO_KEEPALIVE, true)
//                    .childOption(ChannelOption.TCP_NODELAY, false)
                    .childOption(ChannelOption.CONNECT_TIMEOUT_MILLIS, 1000 * 60)//连接超时时间设置为 60 秒
//                    .childOption(ChannelOption.RCVBUF_ALLOCATOR, new NettyRecvByteBufAllocator(1024 * 1024))//用于Channel分配接受Buffer的分配器 默认 AdaptiveRecvByteBufAllocator.DEFAULT
                    .childOption(ChannelOption.WRITE_BUFFER_WATER_MARK, new WriteBufferWaterMark(1024 * 1024, 1024 * 1024 * 2))


                    .childHandler(nettyTcpClientPermeateServerVisitorFilter);

            try {
                 bootstrap.bind(visitorPort).sync().addListener((ChannelFutureListener) future -> {
                    if (future.isSuccess()) {
                        // 这里时异步处理
                        log.info("客户端:[{}]访客端口:[{}] 开启", clientId, visitorPort);
                        Channel channel = future.channel();
                        ChannelAttributeKeyUtils.buildVisitorPort(channel,visitorPort);
                    } else {
                        log.error("客户端:[{}]访客端口:[{}]绑定失败", clientId, visitorPort);
                    }
                });
                NettyVisitorPortContext.pushVisitorSocket(visitorPort, this);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        } else {
            log.warn("客户端渗透服务端:[{}]访客端口:[{}] 重复启动", clientId, visitorPort);
        }

    }
    @Override
    public void close()  {
        PermeateVisitorSocket permeateVisitorSocket = NettyVisitorPortContext.getVisitorSocket(visitorPort);
        if (permeateVisitorSocket != null) {
            log.warn("关闭客户端 :【{}】 访客户端口:【{}】", clientId, visitorPort);
        } else {
            log.warn("关闭访客端口失败 未找到客户端通道 客户端 :【{}】 访客户端口:【{}】", clientId, visitorPort);
        }
    }


    public static final class NettyVisitorSocketBuilder {

        /**
         * 客户端ID
         */
        private String clientId;

        /**
         * 客户端目标地址
         */
        private String clientTargetIp;

        /**
         * 客户端目标端口
         */
        private Integer clientTargetPort;


        /**
         * 访问端口
         */
        private Integer visitorPort;
        /**
         * 服务端地址信息
         */
        private NettyClientProperties nettyClientProperties;

        /**
         * 处理器
         */
        private List<HandleChannelTypeAdvanced> handleChannelTypeAdvancedList;

        public static NettyVisitorSocketBuilder builder() {
            return new NettyVisitorSocketBuilder();
        }

        /**
         * 填充客户端
         *
         * @param clientId 客户端
         * @return 返回当前对象
         */
        public NettyVisitorSocketBuilder builderClientId(String clientId) {
            this.clientId = clientId;
            return this;
        }

        /**
         * 绑定客户端目标IP
         *
         * @param clientTargetIp 客户端目标IP
         * @return 当前对象
         */
        public NettyVisitorSocketBuilder builderClientTargetIp(String clientTargetIp) {
            this.clientTargetIp = clientTargetIp;
            return this;
        }

        /**
         * 绑定客户端目标端口
         *
         * @param clientTargetPort 客户端目标端口
         * @return 当前对象
         */
        public NettyVisitorSocketBuilder builderClientTargetPort(Integer clientTargetPort) {
            this.clientTargetPort = clientTargetPort;
            return this;
        }

        /**
         * 绑定访客端口
         *
         * @param visitorPort 访客端口
         * @return 当前对象
         */
        public NettyVisitorSocketBuilder builderVisitorPort(Integer visitorPort) {
            this.visitorPort = visitorPort;
            return this;
        }

        /**
         * 绑定流量适配器
         *
         * @param handleChannelTypeAdvancedList 流量适配器
         * @return 当前对象
         */
        public NettyVisitorSocketBuilder builderHandleChannelTypeAdvancedList(List<HandleChannelTypeAdvanced> handleChannelTypeAdvancedList) {
            this.handleChannelTypeAdvancedList = handleChannelTypeAdvancedList;
            return this;
        }
        /**
         * 服务端地址信息
         *
         * @param nettyClientProperties 客户服务端地址配置属性
         * @return 返回当前对象
         */
        public NettyVisitorSocketBuilder builderNettyClientProperties(NettyClientProperties nettyClientProperties) {
            this.nettyClientProperties = nettyClientProperties;
            return this;
        }


        public NettyTcpClientPermeateServerVisitorSocket build() {
            if (clientTargetIp == null) {
                throw new IllegalArgumentException("clientTargetIp must not null");
            }
            if (clientTargetPort == null) {
                throw new IllegalArgumentException("clientTargetPort must not null");
            }
            if (visitorPort == null) {
                throw new IllegalArgumentException("visitorPort must not null");
            }
            NettyClientPermeateServerVisitor nettyClientPermeateServerVisitor = new NettyClientPermeateServerVisitor();

            nettyClientPermeateServerVisitor.setTargetIp(clientTargetIp);
            nettyClientPermeateServerVisitor.setTargetPort(clientTargetPort);
            nettyClientPermeateServerVisitor.setVisitorPort(visitorPort);
            nettyClientPermeateServerVisitor.setNettyClientProperties(nettyClientProperties);
            nettyClientPermeateServerVisitor.setHandleChannelTypeAdvancedList(handleChannelTypeAdvancedList);


            NettyTcpClientPermeateServerVisitorFilter nettyTcpClientPermeateServerVisitorFilter = new NettyTcpClientPermeateServerVisitorFilter(nettyClientPermeateServerVisitor);
            return new NettyTcpClientPermeateServerVisitorSocket(nettyTcpClientPermeateServerVisitorFilter, clientId, visitorPort);
        }


    }

}